package modbus_slave

import (
	"backend/internal/core/common"
	"backend/internal/core/types"
	"context"
	"fmt"
	"github.com/goburrow/modbus"
	"github.com/zeromicro/go-zero/core/logx"
	"log"
	"strings"
	"sync"
	"time"
)

// modbusSlaveLogger 自定义 Modbus 从站日志记录器，用于捕获原始报文
type modbusSlaveLogger struct {
	messageQueue *common.MessageQueue
}

// 实现 io.Writer 接口，用于将日志信息写入消息队列
func (l *modbusSlaveLogger) Write(p []byte) (n int, err error) {
	logMsg := string(p)
	// 去除日志信息末尾的换行符
	logMsg = strings.TrimSpace(logMsg)
	// 获取当前时间并格式化
	currentTime := time.Now().Format("2006-01-02 15:04:05.000")

	// 检查是否为接收消息
	if strings.Contains(logMsg, "modbus: received") {
		receivedMsg := strings.TrimPrefix(logMsg, "modbus: received ")
		l.messageQueue.Enqueue(fmt.Sprintf("[%s] RX: %s", currentTime, receivedMsg))
	} else if strings.Contains(logMsg, "modbus: sending") { // 检查是否为发送消息
		sendingMsg := strings.TrimPrefix(logMsg, "modbus: sending ")
		l.messageQueue.Enqueue(fmt.Sprintf("[%s] TX: %s", currentTime, sendingMsg))
	}
	return len(p), nil
}

// ModbusSlave Modbus 从站结构体
type ModbusSlave struct {
	mu           sync.Mutex
	ProtocolType types.ProtocolType
	Server       modbus.Server
	Handler      modbus.ServerHandler
	Running      bool                 // 运行状态
	messageQueue *common.MessageQueue // 消息队列
}

// NewModbusSlave 创建 Modbus 从站实例
func NewModbusSlave(protocolType types.ProtocolType, tcpConfig *types.TcpConfig, rtuConfig *types.RtuConfig) *ModbusSlave {
	// 使用 new 关键字创建 ModbusSlave 类型的指针
	slave := new(ModbusSlave)
	slave.ProtocolType = protocolType
	slave.Running = false
	slave.messageQueue = common.NewMessageQueue(1000) // 初始化消息队列，最大长度 1000

	// 创建自定义日志记录器
	customLogger := &modbusSlaveLogger{
		messageQueue: slave.messageQueue,
	}
	// 使用 log.New 创建 *log.Logger 实例，将自定义日志记录器作为 io.Writer
	logger := log.New(customLogger, "", 0)

	switch protocolType {
	case types.Tcp, types.RtuOverTcp:
		slave.setTcpServer(tcpConfig, logger)
	case types.Rtu:
		slave.setRtuServer(rtuConfig, logger)
	}
	// 直接返回 slave 指针
	return slave
}

// setTcpServer 设置 Tcp 从站服务器
func (s *ModbusSlave) setTcpServer(tcpConfig *types.TcpConfig, logger *log.Logger) {
	switch tcpConfig.ProtocolType {
	case types.Tcp:
		handler := modbus.NewTCPServerHandler(fmt.Sprintf("%s:%d", tcpConfig.Host, tcpConfig.Port))
		handler.SlaveId = 1
		handler.Timeout = 3 * time.Second
		handler.Logger = logger // 设置自定义日志记录器
		s.Server = modbus.NewServer(handler)
		s.Handler = handler
	case types.RtuOverTcp:
		handler := modbus.NewRTUServerHandler(fmt.Sprintf("%s:%d", tcpConfig.Host, tcpConfig.Port))
		handler.SlaveId = 1
		handler.Timeout = 3 * time.Second
		handler.Logger = logger
		s.Server = modbus.NewServer(handler)
		s.Handler = handler
	default:
		panic("unhandled default case")
	}
}

// setRtuServer 设置 Rtu 从站服务器
func (s *ModbusSlave) setRtuServer(rtuConfig *types.RtuConfig, logger *log.Logger) {
	handler := modbus.NewRTUServerHandler(rtuConfig.Port)
	handler.BaudRate = int(rtuConfig.Baudrate)
	handler.DataBits = int(rtuConfig.Bytesize)
	handler.Parity = rtuConfig.Parity
	handler.StopBits = int(rtuConfig.Stopbits)
	handler.SlaveId = 1
	handler.Timeout = 3 * time.Second
	handler.Logger = logger
	s.Server = modbus.NewServer(handler)
	s.Handler = handler
}

// Start 启动 Modbus 从站服务器
func (s *ModbusSlave) Start() bool {
	logx.Debugf("Attempting to start Modbus slave server")

	// 使用互斥锁保证并发安全
	s.mu.Lock()
	defer s.mu.Unlock()

	// 检查 handler 是否为 nil
	if s.Handler == nil {
		logx.Errorf("Modbus slave server handler is nil, cannot start")
		return false
	}

	if s.Running {
		logx.Infof("Modbus slave server is already running")
		return true
	}

	// 尝试进行类型断言，调用 Start 方法
	if starter, ok := s.Handler.(interface{ Start() error }); ok {
		// 设置启动超时
		ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
		defer cancel()

		errChan := make(chan error, 1)
		go func() {
			errChan <- starter.Start()
		}()

		select {
		case err := <-errChan:
			if err != nil {
				logx.Errorf("Failed to start Modbus slave server: %v", err)
				return false
			}
			s.Running = true
		case <-ctx.Done():
			logx.Errorf("Start operation timed out")
			return false
		}
	} else {
		logx.Errorf("Modbus slave server handler does not implement Start method")
		return false
	}

	logx.Infof("Modbus slave server started successfully")
	return true
}

// Stop 停止 Modbus 从站服务器
func (s *ModbusSlave) Stop() {
	// 使用互斥锁保证并发安全
	s.mu.Lock()
	defer s.mu.Unlock()

	// 检查 handler 是否为 nil
	if s.Handler == nil {
		logx.Errorf("Modbus slave server handler is nil, cannot stop")
		return
	}

	// 若已经停止，直接返回
	if !s.Running {
		logx.Infof("Modbus slave server is already stopped")
		return
	}

	// 尝试进行类型断言，调用 Stop 方法
	if stopper, ok := s.Handler.(interface{ Stop() error }); ok {
		// 设置停止超时
		ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
		defer cancel()

		errChan := make(chan error, 1)
		go func() {
			errChan <- stopper.Stop()
		}()

		select {
		case err := <-errChan:
			if err != nil {
				logx.Errorf("Failed to stop Modbus slave server: %v", err)
			}
		case <-ctx.Done():
			logx.Errorf("Stop operation timed out")
		}
	} else {
		logx.Errorf("Modbus slave server handler does not implement Stop method")
	}

	// 更新运行状态
	s.Running = false
	logx.Infof("Modbus slave server stopped")
}

// SetSlaveID 动态设置从站地址
func (s *ModbusSlave) SetSlaveID(slaveID uint8) {
	// 检查 handler 是否为 nil
	if s.Handler == nil {
		logx.Errorf("Modbus slave server handler is nil, cannot set slave ID")
		return
	}
	// 尝试将 handler 转换为具体实现类型的指针
	if tcpHandler, ok := s.Handler.(*modbus.TCPServerHandler); ok {
		tcpHandler.SlaveId = slaveID
		logx.Infof("Successfully set slave ID to %d", slaveID)
	} else if rtuHandler, ok := s.Handler.(*modbus.RTUServerHandler); ok {
		rtuHandler.SlaveId = slaveID
		logx.Infof("Successfully set slave ID to %d", slaveID)
	} else {
		logx.Errorf("Modbus slave server handler does not support setting slave ID")
	}
}

// GetLatestMessage 获取最新的消息
func (s *ModbusSlave) GetLatestMessage() []string {
	var messageList []string
	for !s.messageQueue.IsEmpty() {
		message := s.messageQueue.Dequeue()
		// 进行类型断言
		if msgStr, ok := message.(string); ok {
			messageList = append(messageList, msgStr)
		} else {
			// 记录类型断言失败的日志
			logx.Errorf("Failed to assert message type to string: %v", message)
		}
	}
	logx.Debugf("获取到的消息列表: %v", messageList)
	return messageList
}
